#pragma once
#include <vector>
#include <functional>
#include <sys/epoll.h>
#include "tcp_socket.hpp"

using namespace std;
//只考虑读就绪
typedef function<void(const string& req, string* resp)> Handler;

class Epoll
{
public: 
    Epoll(){
        epoll_fd = epoll_create(10);
    }
    ~Epoll(){
        close(epoll_fd);
    }
    bool Add(const TcpSocket& sock)const{
        int fd = sock.Getfd();
        printf("[Epoll Add] fd = %d\n", fd);
        epoll_event ev;
        ev.data.fd = fd;
        ev.events = EPOLLIN;
        int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
        if(ret < 0){
            perror("epoll_ctl Add");
            return false;
        }
        return true;
    }
    bool Del(const TcpSocket& sock)const{
        int fd = sock.Getfd();
        printf("[Epoll Del] fd = %d\n", fd);
        int ret = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
        if(ret < 0){
            perror("epoll_ctl Del");
            return false;
        }
        return true;
    }
    bool wait(vector<TcpSocket>* output)const{
        output->clear();
        epoll_event ev[1000];
        int nfds = epoll_wait(epoll_fd, ev, sizeof(ev)/sizeof(ev[0]), -1);
        if(nfds < 0){
            perror("epoll_wait");
            return false;
        }
        for(int i = 0; i < nfds; i++){
            TcpSocket sock(ev[i].data.fd);
            output->push_back(sock);
        }
        return true;
    }
private:
    int epoll_fd;
};

class TcpEpollSever
{
public:
    TcpEpollSever(const string& ip, uint16_t port):_ip(ip), _port(port){}
    bool start(Handler handler)
    {
        CHECK_RET(_listensock.Socket());
        CHECK_RET(_listensock.Bind(_ip, _port));
        CHECK_RET(_listensock.Listen(5));
        Epoll epoller;
        epoller.Add(_listensock);

        for(;;)
        {
            vector<TcpSocket> output;
            if(!epoller.wait(&output)){
                continue;
            }
            for(int i = 0; i < output.size(); i++)
            {
                if(output[i].Getfd() == _listensock.Getfd()){
                    TcpSocket new_sock;
                    _listensock.Accept(&new_sock);
                    epoller.Add(new_sock);
                }
                else{
                    string req;
                    int ret = output[i].Recv(&req);
                    if(!ret){//读取失败，或者用户选择退出
                        epoller.Del(output[i]);
                        output[i].Close();
                        continue;
                    }
                    string resp;
                    handler(req, &resp);
                    output[i].Send(resp);
                }
            }
        }
        return true;
    }
private:
    string _ip;
    uint16_t _port;
    TcpSocket _listensock;
};